package com.robertux.leaderboard.servlets;

import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.Locale;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;

import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import com.robertux.leaderboard.beans.JsonResponse;
import com.robertux.leaderboard.beans.RolUsuario;
import com.robertux.leaderboard.beans.TipoMeta;
import com.robertux.leaderboard.beans.entities.DetalleProgresoMeta;
import com.robertux.leaderboard.beans.entities.GrupoProducto;
import com.robertux.leaderboard.beans.entities.ProgresoMeta;
import com.robertux.leaderboard.beans.entities.Usuario;
import com.robertux.leaderboard.beans.entities.external.Sucursal;
import com.robertux.leaderboard.util.MethodExecutionSecurity;
import com.robertux.leaderboard.util.MethodParamsChecker;
import com.robertux.leaderboard.util.gestoresModelos.GestorProgresos;
import com.robertux.leaderboard.util.gestoresModelos.GestorSucursales;
import com.robertux.leaderboard.util.gestoresModelos.GestorUsuarios;

@WebServlet("/ProgresosServlet/*")
public class ProgresosServlet extends BaseServlet {
	private static final long serialVersionUID = 1L;
	private GestorProgresos gPgr = new GestorProgresos();
	private GestorSucursales gSucs = new GestorSucursales();
	private GestorUsuarios gUsrs = new GestorUsuarios();
	private NumberFormat nFmt = new DecimalFormat("#.00");
	private Logger logger = Logger.getLogger(this.getClass());
	private DateFormat dFmt = new SimpleDateFormat("MMMMM yyyy", new Locale("es"));
    
	@MethodExecutionSecurity(requireAuthentication=true, roleLevelAllowed=RolUsuario.VENDEDOR)
    public JsonResponse getMesesProgresos(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
    	JsonResponse jsonResp;
    	JsonArray arr = new JsonArray();
    	
    	Calendar cal = Calendar.getInstance();
    	cal.add(Calendar.MONTH, -3);
    	for(int i=0; i<4; i++) {
    		JsonObject obj = new JsonObject();
    		obj.addProperty("year", cal.get(Calendar.YEAR));
    		obj.addProperty("month", cal.get(Calendar.MONTH)+1);
    		obj.addProperty("label", dFmt.format(cal.getTime()));
    		arr.add(obj);
    		cal.add(Calendar.MONTH, +1);
    	}
    	
    	jsonResp = new JsonResponse(0, "OK", "meses", arr);
    	return jsonResp;
    }
	
	@MethodExecutionSecurity(requireAuthentication=true, roleLevelAllowed=RolUsuario.VENDEDOR)
	public JsonResponse getProgresosUsuario(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
		Usuario usr = null;
		Calendar calHoy = new GregorianCalendar();
		int anio = calHoy.get(Calendar.YEAR), mes = calHoy.get(Calendar.MONTH)+1;
		
		if(req.getParameter("userId") != null && req.getParameter("userId").trim().length() > 0) {
			usr = this.gUsrs.getUsuario(Integer.parseInt(req.getParameter("userId")));
		} else {
			usr = this.getCurrentUsuario(req);
		}
		
		if(req.getParameter("anio") != null && req.getParameter("anio").trim().length() > 0
				&& req.getParameter("mes") != null && req.getParameter("mes").trim().length() > 0) {
			try {
				anio = Integer.parseInt(req.getParameter("anio"));
				mes = Integer.parseInt(req.getParameter("mes"));
			} catch(Exception ex) {
				this.logger.error("Error tratando de parsear el año y mes recibidos: " + ex.getMessage(), ex);
			}
		}
		
		JsonArray arr = new JsonArray();
		
		ResultSet rs = gPgr.getDetalleProgresosUsuario(usr.getId(), anio, mes);
		try {
			while(null != rs && rs.next()) {
				Sucursal suc = this.gSucs.getSucursal(rs.getInt("SUCURSAL"));
				JsonObject pgrObj = new JsonObject(), metaObj = new JsonObject();
				
				pgrObj.addProperty("id", rs.getInt("ID"));
				pgrObj.addProperty("fecha", rs.getString("MES"));
				pgrObj.addProperty("valor", rs.getDouble("PROGRESO"));
				pgrObj.addProperty("ranking", rs.getInt("NOTA"));
				
				TipoMeta tipoMeta = TipoMeta.fromCodigo(rs.getInt("TIPO"));
				metaObj.addProperty("branch", suc != null? suc.getNombre(): "(ninguna)");
				metaObj.addProperty("type", tipoMeta != null? tipoMeta.getNombre().substring(tipoMeta.getNombre().indexOf(" ")): "Evaluaci&ocute;n");
				metaObj.addProperty("metaId", rs.getInt("META_ID"));
				metaObj.addProperty("metaName", rs.getString("META"));
				metaObj.addProperty("value", tipoMeta != null? 
						tipoMeta.equals(TipoMeta.POR_CANT_VENTAS)? 
								rs.getDouble("VALOR") + " unidades": 
								"$ " + nFmt.format(rs.getDouble("VALOR")): 
						String.valueOf(rs.getDouble("VALOR")));
				metaObj.addProperty("weight", rs.getInt("PONDERACION"));
				metaObj.addProperty("isEval", tipoMeta == null);
				
				pgrObj.add("meta", metaObj);
				arr.add(pgrObj);
			}
		} catch (SQLException e) {
			this.logger.error("Error tratando de obtener el detalle de progresos del usuario con ID " + usr.getId() + ": " + e.getMessage(), e);
		} finally {
			try { rs.close(); } catch(Exception ex) { this.logger.warn("No se pudo cerrar el objeto ResultSet luego de la consulta de progresos de usuario: " + ex.getMessage()); }
		}
		
		JsonResponse jsonResp = new JsonResponse(0, "OK", "progresos", arr);
		
		rs = (anio > 0 && mes > 0? gPgr.getTotalProgresosUsuario(usr.getId(), anio, mes): gPgr.getTotalProgresosUsuario(usr.getId()));
		try {
			if(null != rs && rs.next()) {
				jsonResp.add("totalProgresos", new JsonPrimitive(rs.getInt("TOTAL")));
				jsonResp.add("totalPonderacion", new JsonPrimitive(rs.getInt("PONDERACION_TOTAL")));
				jsonResp.add("promedioProgresos", new JsonPrimitive(new BigDecimal(rs.getDouble("PROGRESO_PROMEDIO")).setScale(2, RoundingMode.HALF_UP).doubleValue()));
				jsonResp.add("promedioNotas", new JsonPrimitive(new BigDecimal(rs.getDouble("NOTA_PROMEDIO")).setScale(2, RoundingMode.HALF_UP).doubleValue()));
			}
		} catch (SQLException e) {
			this.logger.error("Error tratando de obtener el total de progresos del usuario con ID " + usr.getId() + ": " + e.getMessage(), e);
		} finally {
			try { rs.close(); } catch(Exception ex) { this.logger.warn("No se pudo cerrar el objeto ResultSet luego de la consulta de progresos de usuario: " + ex.getMessage()); }
		}
		
		return jsonResp;
	}
	
	@MethodExecutionSecurity(requireAuthentication=true, roleLevelAllowed=RolUsuario.JEFE)
	@MethodParamsChecker(requiredParams={"branchId"})
	public JsonResponse getProgresosSucursal(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
		JsonArray arr = new JsonArray();
		Calendar calHoy = new GregorianCalendar();
		int anio = calHoy.get(Calendar.YEAR), mes = calHoy.get(Calendar.MONTH)+1;
		
		GestorProgresos gPgr = new GestorProgresos();
		
		if(req.getParameter("anio") != null && req.getParameter("anio").trim().length() > 0
				&& req.getParameter("mes") != null && req.getParameter("mes").trim().length() > 0) {
			try {
				anio = Integer.parseInt(req.getParameter("anio"));
				mes = Integer.parseInt(req.getParameter("mes"));
			} catch(Exception ex) {
				this.logger.error("Error tratando de parsear el año y mes recibidos: " + ex.getMessage(), ex);
			}
		}
		
		ResultSet rs = gPgr.getDetalleProgresosSucursal(Integer.parseInt(req.getParameter("branchId")), anio, mes);
		try {
			while(null != rs && rs.next()) {
				JsonObject pgrObj = new JsonObject();
				pgrObj.addProperty("usrId", rs.getInt("USUARIO_ID"));
				pgrObj.addProperty("date", rs.getString("MES"));
				pgrObj.addProperty("employee", rs.getString("VENDEDOR"));
				pgrObj.addProperty("value", new BigDecimal(rs.getDouble("PROGRESO_TOTAL")).setScale(2, RoundingMode.HALF_UP).doubleValue());
				pgrObj.addProperty("weight", rs.getInt("PONDERACION_TOTAL"));
				pgrObj.addProperty("ranking", rs.getInt("NOTA"));
				pgrObj.addProperty("total", rs.getInt("METAS"));
				arr.add(pgrObj);
			}
		} catch (SQLException e) {
			this.logger.error("Error tratando de obtener el total de progresos de la sucursal con ID " + req.getParameter("branchId") + ": " + e.getMessage(), e);
		} finally {
			try { rs.close(); } catch(Exception ex) { this.logger.warn("No se pudo cerrar el objeto ResultSet luego de la consulta de progresos de sucursal: " + ex.getMessage()); }
		}
		
		JsonResponse jsonResp = new JsonResponse(0, "OK", "progresos", arr);
		
		rs = (anio > 0 && mes > 0? gPgr.getTotalProgresosSucursal(Integer.parseInt(req.getParameter("branchId")), anio, mes): gPgr.getTotalProgresosSucursal(Integer.parseInt(req.getParameter("branchId"))));
		try {
			if(null != rs && rs.next()) {
				jsonResp.add("totalProgresos", new JsonPrimitive(rs.getInt("TOTAL")));
				jsonResp.add("totalPonderacion", new JsonPrimitive(rs.getInt("PONDERACION_TOTAL")));
				jsonResp.add("promedioProgresos", new JsonPrimitive(new BigDecimal(rs.getDouble("PROGRESO_TOTAL")).setScale(2, RoundingMode.HALF_UP).doubleValue()));
			}
		} catch (SQLException e) {
			this.logger.error("Error tratando de obtener el total de progresos de la sucursal con ID " + req.getParameter("branchId") + ": " + e.getMessage(), e);
		} finally {
			try { rs.close(); } catch(Exception ex) { this.logger.warn("No se pudo cerrar el objeto ResultSet luego de la consulta de progresos de sucursal: " + ex.getMessage()); }
		}
		return jsonResp;
	}
	
	@MethodExecutionSecurity(requireAuthentication=true, roleLevelAllowed=RolUsuario.GERENTE)
	public JsonResponse getProgresosGeneral(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
		JsonArray arr = new JsonArray();
		List<JsonObject> sortedJsonItems = new ArrayList<JsonObject>();
		ResultSet rs = null;
		Calendar calHoy = new GregorianCalendar();
		
		if(req.getParameter("supervisorId") != null) {
			rs = new GestorProgresos().getDetalleProgresosGeneral(Integer.parseInt(req.getParameter("supervisorId")), calHoy.get(Calendar.YEAR), calHoy.get(Calendar.MONTH)+1);
		} else {
			rs = new GestorProgresos().getDetalleProgresosGeneral(calHoy.get(Calendar.YEAR), calHoy.get(Calendar.MONTH)+1);
		}
		
		try {
			while(null != rs && rs.next()) {
				Sucursal suc = this.gSucs.getSucursal(rs.getInt("SUCURSAL_ID"));
				
				JsonObject pgrObj = new JsonObject();
				pgrObj.addProperty("branchId", suc != null? suc.getId(): 0);
				pgrObj.addProperty("branchName", suc != null? suc.getNombre(): "(ninguna)");
				pgrObj.addProperty("branch", suc != null? suc.getId() + " - " + suc.getNombre(): "0 - (ninguna)");
				pgrObj.addProperty("date", rs.getString("MES"));
				pgrObj.addProperty("supervisor", rs.getString("SUPERVISOR"));
				pgrObj.addProperty("employees", rs.getInt("VENDEDORES_TOTAL"));
				pgrObj.addProperty("value", new BigDecimal(rs.getDouble("PROGRESO_TOTAL")).setScale(2, RoundingMode.HALF_UP).doubleValue());
				pgrObj.addProperty("value_1", new BigDecimal(rs.getDouble("PROGRESO_TOTAL_ANT")).setScale(2, RoundingMode.HALF_UP).doubleValue());
				pgrObj.addProperty("value_2", new BigDecimal(rs.getDouble("PROGRESO_TOTAL_ANT2")).setScale(2, RoundingMode.HALF_UP).doubleValue());
				pgrObj.addProperty("value_3", new BigDecimal(rs.getDouble("PROGRESO_TOTAL_ANT3")).setScale(2, RoundingMode.HALF_UP).doubleValue());
				sortedJsonItems.add(pgrObj);
				//arr.add(pgrObj);
			}
			
			Collections.sort(sortedJsonItems, new Comparator<JsonObject>() {
				@Override
				public int compare(JsonObject o1, JsonObject o2) {
					return o1.get("branchName").getAsString().compareTo(o2.get("branchName").getAsString());
				}
			});
			
			for(JsonObject jsonObj: sortedJsonItems) {
				arr.add(jsonObj);
			}
		} catch (SQLException e) {
			this.logger.error("Error tratando de obtener el total de progresos general: " + e.getMessage(), e);
		} finally {
			try { rs.close(); } catch(Exception ex) { this.logger.warn("No se pudo cerrar el objeto ResultSet luego de la consulta de progresos general: " + ex.getMessage()); }
		}
		
		JsonResponse jsonResp = new JsonResponse(0, "OK", "progresos", arr);
		return jsonResp;
	}
	
	@MethodExecutionSecurity(requireAuthentication=true, roleLevelAllowed=RolUsuario.VENDEDOR)
	@MethodParamsChecker(requiredParams={"progresoId"})
	public JsonResponse getDetalleProgreso(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
		ProgresoMeta progreso = this.gPgr.getProgreso(Integer.parseInt(req.getParameter("progresoId")));
		TipoMeta tipoMeta = TipoMeta.fromCodigo(progreso.getMeta().getTipo());
		
		JsonArray arr = new JsonArray();
		for(DetalleProgresoMeta detalle: progreso.getDetalleProgresosMeta()) {
			this.logger.debug("Agregando detalle " + detalle);
			GrupoProducto gPrd = detalle.getGrupoProducto();
			JsonObject obj = new JsonObject();
			obj.addProperty("gPrdId", gPrd.getId());
			obj.addProperty("gPrdNombre", gPrd.getNombre());
			obj.addProperty("totalVentas", tipoMeta.equals(TipoMeta.POR_CANT_VENTAS)? (detalle.getTotalVentas().doubleValue() + " unidades"): 
				("$ " + detalle.getTotalVentas().doubleValue()));
			arr.add(obj);
		}
		
		return new JsonResponse(0, "OK", "ventasMeta", arr);
	}
	
	@MethodExecutionSecurity(requireAuthentication=true, roleLevelAllowed=RolUsuario.GERENTE, method="GET,POST")
	public JsonResponse descargarProgreso(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
		byte[] archivo = new GestorProgresos().generarArchivoProgresos();
		
        resp.setHeader("Content-disposition","attachment; filename=reporteProgresosVentas.xls");
        resp.setContentType("application/vnd-ms-excel");
        resp.setContentLength(archivo.length);
        
        resp.getOutputStream().write(archivo);
        resp.getOutputStream().flush();
        resp.getOutputStream().close();
		
		return new JsonResponse();
	}
	
	@MethodExecutionSecurity(requireAuthentication=true, roleLevelAllowed=RolUsuario.VENDEDOR)
	public JsonResponse recalcularProgresoUsuario(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
		return new JsonResponse();
	}

}
